/*
	Class: FormCheck
		Performs different tests on forms and highlight errors.
		
	Usage:
		Works with these types of fields :
		- input (text, radio, checkbox)
		- textarea
		- select
		
		You just need to add classes to fields you want to be checked (at least the 'required' class).
		Avalaible test are :
		- required
		- phone
		- digit
		- minchar (2 characteres at least)
		- email
		
		If you use NiceMooForms.js inside FormCheck.js (by setting 'use_NiceMooForms' to true), be careful to load this class BEFORE FormChack.js in the html, otherwise it won't work.

	Parameters:
		form_id - The id of the formular. By default it is 'mainform'.
		use_NiceMooForms - Set this option to true if you want to use formcheck with class NiceMooForms.js (moo.floor.ch). This option disable the 'add_span' parameter.
		error_class - The class to apply to fields with error. By default it is 'error_f'.
		span_class - Class of radios and checkbox span injection (if used). By default it is 'tmp42', but normally you don't need to change this setting.
		add_span : Inject checkbox and radio into <span> so we can set an error style to it ('error_f'). By default it is false.
		highlight - Choose if you want to highlight errors. 0 : highlight none, 1 : highlight one, 2 : highlight all. By default it is 1.
		scroll_to_error - Smooth scroll the page to first error, by default it is set on true.
		
	Exemple:
		You can initialize a formcheck by adding this in your html head this code :
		
		(code)
		<script type="text/javascript">
			window.addEvent('domready', function() {
				var myFormCheck = new FormCheck({
					form_id : 'mainform',
					use_NiceMooForms : true,
					error_class : 'error_f',
					highlight : 2,
					scroll_to_error : false
				 });
			});
		</script>
		(end code)
	
	Require:
	(code)
		Core
		
		    * Core.js
		
		Class
		
		    * Class.js
		
		Native
		
		    * Array.js
		    * String.js
		    * Function.js
		    * Number.js
		    * Element.js
		
		Element
		
		    * Element.Filters.js
		    * Element.Selectors.js
	(end code)
	
	About:
		formcheck.js v.1.0 for mootools v1.1 05 / 2007
		
		by Floor SA (http://www.floor.ch) MIT-style license
		
		Created by Luca Pillonel and David Mignot, last modified by Luca Pillonel 30.05.12
	
*/
var FormCheck = new Class({
	options: {
		form_id: 'mainform',		//the target form id
		use_NiceMooForms : false,	//if we want to use NiceMooForms
		error_class: 'error_f',		//highlight error class
		add_span : false,			//inject checkbox and radio into span so we can set an error style
		span_class: 'tmp42',		//class to highlight radios and checkbox span (if used)
		highlight : 1,				//0 : highlight none, 1 : one, 2 : all
		scroll_to_error : true		//smooth scroll the page to first error
	},
	/*
	Constructor: initialize
		Constructor
	
		Add event on formular and perform some stuff, you now, like settings, ...
	*/
	initialize: function(options){
		//Initialize some vars
		this.setOptions(options);
		this.errorArray = [];
		this.radioArray = [];
		
		// For compatibility, if form_id doesn't exist, check all forms for a "name='form_id'"
		if(!$(this.options.form_id)){
			$$('form').each(function(el){
				if(el.getAttribute('name') == this.options.form_id){
					el.setProperty('id', this.options.form_id);
				}
			}.bind(this));
		}
		if(!$(this.options.form_id)){
			return 0;
		}
		
		//Launch NiceMooForms if needed
		if (this.options.use_NiceMooForms == true) {
		//	this.niceForm = new NiceMooForms({
		//			form_id : this.options.form_id
		//		});
		}
		
		//Add an event on submit action
		$(this.options.form_id).addEvent('submit', function(e) {
			// Do our validation:
			if (this.options.highlight > 0 && this.errorArray.length != 0) {
				this.errorArray.each(function(el) {
					el.removeClass(this.options.error_class);
				}.bind(this));
			}
			this.errorArray = [];
			this.validate();
			if (this.errorArray.length != 0) {
				switch(this.options.highlight.toInt()) {
					case 1 :	this.errorArray[0].addClass(this.options.error_class);
								break;
					case 2 :	this.errorArray.each(function (el) {
									el.addClass(this.options.error_class);
								}.bind(this));
								break;
				}
				
				this.focusOn.pass(this.errorArray[0]).delay(500);
				if (this.options.scroll_to_error) new Fx.Scroll(window).scrollTo(0,this.errorArray[0].getCoordinates().top - 30);
				new Event(e).stop();
			}
		}.bind(this));
		//Make an array with radios
		$$("input").each(function(el){
			if (el.type == "radio") { this.radioArray.push(el);}
		}.bind(this));
	},
	focusOn: function(error) {
		error.focus();
	},
	/*
	Function: validate
		Private method
		
		Add listener on submit action and launch check process.
	*/
	validate: function(){
		$ES('.required', this.options.form_id).each(function(el){
			switch(true) {
				case el.getTag() == "input" && el.hasClass('email') : 
					this.validateEmail(el);
					break;
				case el.getTag() == "input" && el.hasClass('phone') : 
					this.validatePhone(el);
					break;
				case el.getTag() == "input" && el.hasClass('minchar') : 
					this.validateMinChar(el);
					break;
				case el.getTag() == "input" && el.hasClass('digit') : 
					this.validateDigit(el);
					break;
				case (el.getTag() == "input" && el.type == "text") : 
					this.validateText(el);
					break;
				case el.getTag() == "input" && !el.type: 
					this.validateText(el);
					break;
				case el.getTag() == "textarea" :
					this.validateText(el);
					break;
				case el.getTag() == "select" :
					this.validateSelect(el);
					break;
				case el.getTag() == "input" && el.type == "radio" : 
					this.validateRadio(el);
					break;
				case el.getTag() == "input" && el.type == "checkbox" : 
					this.validateCheckbox(el);
					break;
			}
		}.bind(this));
	},
	/*
	Method: injectInsideSpan
		Private method
		
		Insert the element into a span and return the span.
		
	Parameters:
		el - html element
		
	Return:
		html element - the span containing the element.
	*/
	injectInsideSpan: function(el){
		if (el.getParent().hasClass(this.options.span_class)) {
			return el.getParent();
		} else {
			var span = new Element("span", {'class' : this.options.span_class}).injectBefore(el);
			el.injectInside(span);
			return span;
		}
	},
	/*
	Method: validateMinChar
		Private method
		
		Check if the element value contains more than two characteres, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validateMinChar: function(el){
		if(el.value.length < 2){
			this.errorArray.push(el);
		}
	},
	/*
	Method: validateDigit
		Private method
		
		Check if the element value contains only digits, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validateDigit: function(el){
		if (el.value.test('^[0-9]+$') == false) {
			this.errorArray.push(el);
		}
	},
	/*
	Method: validateEmail
		Private method
		
		Check if the element value is a valid email, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validateEmail: function(el){
		if (el.value.test('^.+@.+\\.[a-z]+$') == false) {
			this.errorArray.push(el);
		}
	},
	/*
	Method: validatePhone
		Private method
		
		Check if the element value contains a valid (more or less) phone number, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validatePhone: function(el){
		if (el.value.test('^([0-9]|[\(\)\+\.\ \-])+$') == false) {
			this.errorArray.push(el);
		}
	},
	/*
	Method: validateText
		Private method
		
		Check if the element value contains at least something, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validateText: function(el){
		if(el.value.length < 1 || el.value == ''){
			this.errorArray.push(el);
		}
	},
	/*
	Method: validateSelect
		Private method
		
		Check if select is selected, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validateSelect: function(el){
		if(el.value == el.options[0].value) {
			this.errorArray.push(el);
		}
	},
	/*
	Method: niceFormOrSpan
		Private method
		
		Check how element should be show and add it to error array.
		
	Parameters:
		el - html element
	*/
	niceFormOrSpan : function(el) {
		switch(true) {
			case this.options.add_span == true && this.options.use_NiceMooForms == false :
				this.errorArray.push(this.injectInsideSpan(el));
				break;
			case this.options.use_NiceMooForms == true :
				if (el.getNext()) this.errorArray.push(el.getNext());
				break;
			default : 
				this.errorArray.push(el);
				break;
		}
	},	
	/*
	Method: validateRadio
		Private method
		
		Check if a radio box is checked, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validateRadio: function(el){
		var sameRadio = [];
		var valid = false;
		this.radioArray.each(function(el2){
			if (el2.name == el.name  && el2.checked == false ) { 
				sameRadio.push(el2);
			} else {
				valid = true;
			}
		});
		//We check if there is a false for every required
		if (valid == false) {
			sameRadio.each(function(el2) {
				this.niceFormOrSpan(el2);
			}.bind(this));
		}
	},
	/*
	Method: validateCheckbox
		Private method
		
		Check if checkbox is checked, otherwise it add it to an error array.
		
	Parameters:
		el - html element
	*/
	validateCheckbox: function(el){
		if(el.checked == false){
			this.niceFormOrSpan(el);
		}
	}
});

FormCheck.implement(new Options);